package thread;

public class Demo14 {
    private static int count1 = 0;
    public static void main1(String[] args) {
        //线程安全问题
        Thread t1 = new Thread(() -> {
            for(int i = 0;i < 50000;i++) {
                count1++;
            }
            System.out.println("t1结束");
        });

        Thread t2 = new Thread(() -> {
           for(int i = 0;i < 50000;i++) {
               count1++;
           }
            System.out.println("t2结束");
        });

        t1.start();
        t2.start();

        //我们的 t1 和 t2 都进行 5w 次加count1，所以最终应该是 10w 次
        System.out.println(count1);//-> count1 = 0
        //这是因为呢我们这里有三个线程，进行随机调度，会先调度 main 线程，而 t1 和 t2 没有进行打印，所以就是0
    }

    private static int count2 = 0;
    public static void main2(String[] args) throws InterruptedException {
        //进行更改，我们把 main线程 进行 “等待” t1 和 t2线程的执行
        Thread t1 = new Thread(() -> {
            for(int i = 0;i < 50000;i++) {
                count2++;
            }
            System.out.println("t1结束");
        });

        Thread t2 = new Thread(() -> {
            for(int i = 0;i < 50000;i++) {
                count2++;
            }
            System.out.println("t2结束");
        });

        t1.start();
        t2.start();

        //这里谁先等待都可以
        t1.join();
        t2.join();

        System.out.println(count2);// -> 得到 51258，并非是 10w ，并且这个结果是会变更的，并非是一个定值，这是什么问题？
        //这个是 多线程并发进行的问题，我们将其变成 串行进行就可以了
    }

    private static int count3 = 0;
    public static void main3(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for(int i = 0;i < 50000;i++) {
                count3++;
            }
            System.out.println("t1结束");
        });

        Thread t2 = new Thread(() -> {
            for(int i = 0;i < 50000;i++) {
                count3++;
            }
            System.out.println("t2结束");
        });
        //先把t1执行之后再执行t2
        //这个就是串行执行，一个执行完成之后再执行下一个
        t1.start();
        t1.join();

        t2.start();
        t2.join();

        System.out.println(count3);
    }
    //这种由于 多线程并发执行的情况下出现的 bug 就是“线程安全问题”

    private static int count4 = 0;
    public static void main4(String[] args) throws InterruptedException {
        //解决线程安全问题，我们使用 锁synchronized 来解决这个问题
        Object locker = new Object();

        Thread t1 = new Thread(() -> {
           for(int i = 0;i < 50000; i++) {
               synchronized(locker) {//这里的锁的() 里可以使任何的对象，对于这个类型是不重要的
                   //但是重要的是我们是否有多个线程尝试针对同一个对象加锁
                   count4++;
               }
           }
            System.out.println("t1 结束");
        });

        Thread t2 = new Thread(() -> {
           for(int i = 0; i < 50000;i++) {
               synchronized(locker) {
                   count4++;
               }
           }
            System.out.println("t2 结束");
        });
        //两个线程，针对同一个对象加锁，才会产生排斥现象
        //排斥现象就是：一个线程加锁，另一个线程就得 阻塞等待 ，只能等加锁的对象解锁了，才能进行下一个对象的执行
        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println(count4);
    }

    //如果是两个线程对于不同的对象进行 锁 操作的话，就不会出现 排斥现象
    private static int count5 = 0;
    public static void main5(String[] args) throws InterruptedException {
        //解决线程安全问题，我们使用 锁synchronized 来解决这个问题
        Object locker = new Object();
        Object locker2 = new Object();

        Thread t1 = new Thread(() -> {
            for(int i = 0;i < 50000; i++) {
                synchronized(locker) {//这里的锁的() 里可以使任何的对象，对于这个类型是不重要的
                    //但是重要的是我们是否有多个线程尝试针对同一个对象加锁
                    count5++;
                }
            }
            System.out.println("t1 结束");
        });

        Thread t2 = new Thread(() -> {
            for(int i = 0; i < 50000;i++) {
                synchronized(locker2) {
                    count5++;
                }
            }
            System.out.println("t2 结束");
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println(count5);
    }

    //我们的对象也可以是 currentThread() 得出的线程对象进行 锁对象操作,但是这样写有点奇怪
    private static int count6 = 0;
    public static void main(String[] args) throws InterruptedException {
        //解决线程安全问题，我们使用 锁synchronized 来解决这个问题

        Thread t1 = new Thread(() -> {
            Thread cur = Thread.currentThread();
            for(int i = 0;i < 50000; i++) {
                synchronized(cur) {//这里的锁的() 里可以使任何的对象，对于这个类型是不重要的
                    //但是重要的是我们是否有多个线程尝试针对同一个对象加锁
                    count6++;
                }
            }
            System.out.println("t1 结束");
        });

        Thread t2 = new Thread(() -> {
            for(int i = 0; i < 50000;i++) {
                synchronized(t1) {
                    count6++;
                }
            }
            System.out.println("t2 结束");
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println(count6);
    }
}
